package com.zwh.tool.utils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 了解HashMap底层时可用到的工具类
 */
public class MapUtils {

    static final int MAXIMUM_CAPACITY = 1 << 30;

    /**
     * 由于HashMap没有获取阈值的公共方法,因此反射来拿到(所谓阈值,就是容量×负载因子)
     * @see HashMap#threshold
     */
    public static Object getHashMapThreshold(Map<?, ?> map) {
        try {
            Class<? extends Map> mapType = map.getClass();
            Field threshold = mapType.getDeclaredField("threshold");
            threshold.setAccessible(true);
            return threshold.get(map);
        }
        catch (NoSuchFieldException | IllegalAccessException e){
            System.out.println("\033[31;4m" + e + "\033[0m");
        }
        return -1;
    }

    /**
     * 由于HashMap没有获取容量的公共方法,因此反射来拿到
     * @see HashMap#capacity()
     */
    public static Object getHashMapCapacity(Map<?, ?> map) {
        Class<? extends Map> mapType = map.getClass();
        //获取指定方法，HashMap没有容量这个属性，但是capacity方法会返回容量值
        try {
            Method capacity = mapType.getDeclaredMethod("capacity");
            capacity.setAccessible(true);
            return capacity.invoke(map);
        } catch (NoSuchMethodException | IllegalAccessException|InvocationTargetException e) {
            System.out.println("\033[31;4m" + e + "\033[0m");
        }
        return -1;
    }

    /**
     * 模拟HashMap初始化阈值的操作(根据逻辑右移,所以到一个度之后运算的都是0,所以就固定到某个值去了)
     * @see HashMap#tableSizeFor(int)
     */
    public static int tableSizeFor(int cap) {
        int n = cap - 1;
        System.out.println(Integer.toBinaryString(n));
        System.out.println(Integer.toBinaryString(n >>> 1));
        n |= n >>> 1;
        System.out.println(Integer.toBinaryString(n));
        System.out.println(Integer.toBinaryString(n >>> 2));
        n |= n >>> 2;
        System.out.println(Integer.toBinaryString(n));
        System.out.println(Integer.toBinaryString(n >>> 4));
        n |= n >>> 4;
        System.out.println(Integer.toBinaryString(n));
        System.out.println(Integer.toBinaryString(n >>> 8));
        n |= n >>> 8;
        System.out.println(Integer.toBinaryString(n));
        System.out.println(Integer.toBinaryString(n >>> 16));
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }
}
